﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

#pragma warning disable 0618

namespace PP.Basic
{
    public static partial class GameObjectExtension
    {
        public static bool IsSetActiveSelfEventEnabled = false;
        public static event Action<GameObject> SetActiveSelfEvent;

        public static void SetActiveSelf(this GameObject go, bool active)
        {
            if (IsSetActiveSelfEventEnabled)
            {
                // 触发事件，用于额外分析
                SetActiveSelfEvent?.Invoke(go);
            }
            go?.SetActive(active);
        }

        public static void SetActiveEx(this GameObject go, bool active, bool isRecursive = true)
        {
            if (go == null)
                return;
            if (isRecursive)
                go.SetActiveRecursively(active);
            else
                go.SetActiveSelf(active);
        }

        /// <summary>
        /// Set the layer to the given object and the full hierarchy below it.
        /// </summary>
        /// <param name="go">Start point of the traverse</param>
        /// <param name="layer">The layer to apply</param>
        /// <param name="isSelfIncluded">Indicates whether go should be set or not</param>
        public static void SetLayerRecursively(this GameObject go, int layer, bool isSelfIncluded = false)
        {
            if (go == null)
                return;

            if (isSelfIncluded)
            {
                go.layer = layer;
            }

            foreach (var child in go.transform.EnumerateHierarchy())
            {
                child.gameObject.layer = layer;
            }
        }

        public static void ActiveChild(this GameObject parent, int index, bool active = true, bool isRecursive = false)
        {
            if (parent == null)
                return;
            parent.transform.ActiveChild(index, active, isRecursive);
        }

        public static void ActiveChildren(this GameObject parent, bool active = true, bool isRecursive = false)
        {
            if (parent == null)
                return;
            parent.transform.ActiveChildren(active, isRecursive);
        }


        public static void DeactiveChild(this GameObject parent, int index, bool isRecursive = false)
        {
            if (parent == null)
                return;
            parent.transform.ActiveChild(index, false, isRecursive);
        }

        public static void DeactiveChildren(this GameObject parent, bool isRecursive = false)
        {
            if (parent == null)
                return;
            parent.transform.ActiveChildren(false, isRecursive);
        }


        public static void DestroyChildren(this GameObject go, bool immediate = false)
        {
            if (go == null)
                return;
            go.transform.DestroyChildren(immediate);
        }

        public static void DestroyChildrenEx(this GameObject go, bool immediate = false)
        {
            if (go == null)
                return;
            go.transform.DestroyChildrenEx(immediate);
        }

        /// <summary>
        /// 会先激活所有GameObject，再销毁。
        /// 如此确保OnDestroy函数在销毁时被调用。
        /// 需要使用者自行把控相关流程。比如注意因此引起的OnEnable调用。
        /// </summary>
        public static void DestroyEx(this GameObject go, bool immediate = false)
        {
            if (go == null)
                return;

#if UNITY_EDITOR
            Debug.LogWarning("This is a special method. Please make sure it's necessary to be called.");
#endif

            go.SetActiveRecursively(true);
            if (immediate)
            {
                GameObject.DestroyImmediate(go);
            }
            else
            {
                GameObject.Destroy(go);
            }
        }

        /// <summary>
        /// 销毁所有子节点
        /// </summary>
        /// <param name="go">根节点</param>
        /// <param name="isDestroyNow">调用OnDispose方法后，是否需要调用Destroy销毁子节点，默认 true 销毁子节点</param>
        /// <param name="immediate">是否立即销毁，Unity默认 false，不立即销毁</param>
        public static void DisposeChildren(this GameObject go, bool isDestroyNow = true, bool immediate = false)
        {
            if ((object)go == null)
                return;

            go.transform.DisposeChildren(isDestroyNow, immediate);
        }

        /// <summary>
        /// 销毁所有其它子节点
        /// </summary>
        /// <param name="go">根节点</param>
        /// <param name="targetChildTrans">需要保留的子节点</param>
        /// <param name="isDestroyNow">调用OnDispose方法后，是否需要调用Destroy销毁子节点，默认 true 销毁节点</param>
        /// <param name="immediate">是否立即销毁，Unity默认 false，不立即销毁</param>
        public static void DisposeOtherChildren(this GameObject go, Transform targetChildTrans, bool isDestroyNow = true, bool immediate = false)
        {
            if ((object)go == null)
                return;

            go.transform.DisposeOtherChildren(targetChildTrans, isDestroyNow, immediate);
        }

        public static Component AddComponentEx(this GameObject go, Type t)
        {
            Component o = go.GetComponent(t);
            if (o == null)
            {
                o = go.AddComponent(t);
            }
            return o;
        }

        public static T AddComponentEx<T>(this GameObject go) where T : Component
        {
            T o = go.GetComponent<T>();
            if (o == null)
            {
                o = go.AddComponent<T>();
            }
            return o;
        }

        public static T GetComponentEx<T>(this GameObject go) where T : Component
        {
            T o = go.GetComponent<T>();
            if (o == null)
            {
                o = go.AddComponent<T>();
            }
            return o;
        }

        public static Vector2 RectTransformSizeEx(this GameObject go)
        {
            if (go == null)
            {
                return Vector2.zero;
            }
            return go.transform.RectTransformSizeEx();
        }

        public static void WalkThrough(this GameObject go, Action<GameObject> action, bool isSelfIncluded = false)
        {
            if (!go || action == null)
                return;

            if (isSelfIncluded)
            {
                action(go);
            }

            foreach (var child in go.transform.EnumerateHierarchy())
            {
                action(child.gameObject);
            }
        }
    }
}
